#!/usr/bin/env python3
#coding=utf-8

import yaml
import json
import sys

### 配置部分
# k8s stdout默认sls logstore
stdout_logstore = "k8s-stdout"
# volume pvc包含种类
volume_pvc_types = ["nas", "oss"]
# 生成deployment yaml文件路径
deployment_yaml_path = "."
# deployment 模版路径
deployment_template_path = "./template"
# cpu,mem个性化设置服务
## 资源最大允许值
cpu_limit_max_set = 4
mem_limit_max_set = 4
gpu_mem_limit_max_set = 6
## 资源默认允许值
cpu_limit_default_set = 1
mem_limit_default_set = 2
gpu_mem_limit_default_set = 3

class Deploy(object):
  def __init__(self, appconf) -> None:
    """"""
    self.appconf = appconf

  def appConf(self):
    """获取应用配置,并结构化"""
    with open(self.appconf, 'r', encoding='utf-8') as f:
      app_conf = f.read()
      app_conf = yaml.load(app_conf, Loader=yaml.FullLoader)
    return app_conf

  def deploymentYaml(self, servicename, **kwargs):
    """生成deployment yaml文件,通过判断hostType获取模版文件"""
    servicename = servicename

    image = kwargs['image']
    namespace = kwargs['namespace']
    # nodeDeployAppLabel目前仅支持gpu服务选节点标签
    nodeDeployAppLabel = kwargs['nodeDeployAppLabel']

    # app_conf 获取应用配置
    app_conf = self.appConf()
    appPort = app_conf['appPort']
    hostType = app_conf['hostType']
    replicats = app_conf['replicats']
    # 只生产环境支持资源大小指定，非生产不支持
    if "pro" in namespace:
      cpu_limit = int(app_conf.get('cpuLimit', cpu_limit_default_set))
      cpu_limit = cpu_limit_max_set if cpu_limit > cpu_limit_max_set else cpu_limit
      mem_limit = int(app_conf.get('memLimit', mem_limit_default_set))
      mem_limit = mem_limit_max_set if mem_limit > mem_limit_max_set else mem_limit
      gpu_mem_limit = int(app_conf.get('gpuMemLimit', gpu_mem_limit_default_set))
      gpu_mem_limit = gpu_mem_limit_max_set if gpu_mem_limit > gpu_mem_limit_max_set else gpu_mem_limit
    else:
      cpu_limit = 1
      mem_limit = 1
      gpu_mem_limit = 3
    # 非生产环境 replicats=1
    replicats = app_conf['replicats'] if namespace.strip() == "pro" else 1
    # 动态识别cpu/gpu模版
    if "cpu" in hostType: hostType = "cpu"
    if "gpu" in hostType: hostType = "gpu"
    templatefile = "%s/deployment-%s-template.yaml" % (deployment_template_path, hostType)
    with open(templatefile) as f:
      deploy_str = f.read()
      if hostType == "cpu": deployment_str = deploy_str.format(name=servicename, appPort=appPort, hostType=hostType, replicats=replicats, image=image, namespace=namespace, cpu_limit=cpu_limit, mem_limit=mem_limit)
      if hostType == "gpu": deployment_str = deploy_str.format(name=servicename, appPort=appPort, hostType=hostType, replicats=replicats, image=image, namespace=namespace, cpu_limit=cpu_limit, mem_limit=mem_limit, gpu_mem_limit=gpu_mem_limit, nodeDeployAppLabel=nodeDeployAppLabel)

      deployment = yaml.load(deployment_str, Loader=yaml.FullLoader)
    return deployment

  def updateDeployment(self, deployment, env):
    """更新deployment其他结构部分"""
    # app_conf 获取应用配置
    app_conf = self.appConf()

    # 依据配置设置日志部分
    logs_map = []
    # 扩展自定义env功能
    if app_conf.get('env'):
      for k, v in app_conf.get('env').items():
        logs_map.append({'name': k, 'value': str(v)})

    if env == "pro":
      app_conf_containerLog = app_conf['containerLog']
      # 预定义容器日志接收变量
      #if app_conf_containerLog.get('stdout'):
      # name = "aliyun_logs_%s" % stdout_logstore
      # logs_map.append({'name': name, 'value': 'stdout'})
 
      #if app_conf_containerLog.get('applog'):
      #  logstore = app_conf_containerLog['applog'][0]['logstore']
      #  logPath = app_conf_containerLog['applog'][0]['logPath']
      #  name = "aliyun_logs_%s" % logstore
      #  logs_map.append({'name': name, 'value': logPath})
 
      if app_conf_containerLog.get('eventlog'):
        project = app_conf_containerLog['eventlog'][0]['project']
        logstore = app_conf_containerLog['eventlog'][0]['logstore']
        logtail = app_conf_containerLog['eventlog'][0]['logtail']
        logPath = app_conf_containerLog['eventlog'][0]['logPath']
        # 设置event日志部分
        event_name = "aliyun_logs_%s" % logtail
        logs_map.append({'name': event_name, 'value': logPath})
        # 设置event project
        event_project = "%s_project" % event_name
        logs_map.append({'name': event_project, 'value': project})
        # 设置event project
        event_logstore = "%s_logstore" % event_name
        logs_map.append({'name': event_logstore, 'value': logstore})

    if logs_map:
      # 更新日志配置, 当container存在env, 则追加;否则,直接更新配置信息
      container = deployment['spec']['template']['spec']['containers'][0]
      if container.get('env'):
       for _ in logs_map:
         deployment['spec']['template']['spec']['containers'][0]['env'].append(_)
      else:
       deployment['spec']['template']['spec']['containers'][0]['env'] = logs_map
      # print(container)

    # 依据配置，设置volume部分
    app_conf_volumes = app_conf.get('volumes')
    if app_conf_volumes:
      for _ in app_conf_volumes:
        vtype = _['type']
        if vtype in volume_pvc_types:
          (pvcName, vmountPath) = (_['pvcName'], _['mountPath'])
          vname = "volume-%s" % pvcName
          # 更新volume, 当deployment存在volumes，则添加; 当不存在volumes,则配置
          if deployment['spec']['template']['spec'].get("volumes"):
            deployment['spec']['template']['spec']['volumes'].append({'name': vname, 'persistentVolumeClaim': {'claimName': pvcName}})
          else:
            deployment['spec']['template']['spec']['volumes'] = {'name': vname, 'persistentVolumeClaim': {'claimName': pvcName}}

          # 更新volumeMounts [{'name': volume-localtime, 'mountPath': /etc/localtime}]
          if deployment['spec']['template']['spec']['containers'][0].get("volumeMounts"):
            deployment['spec']['template']['spec']['containers'][0]['volumeMounts'].append({'name': vname, 'mountPath': vmountPath})
          else:
            deployment['spec']['template']['spec']['containers'][0]['volumeMounts'] = {'name': vname, 'mountPath': vmountPath}

    return deployment
  
  def writeFile(self, servicename, deployment, namespace):
    import os
    # 目录不存在则创建
    file_path = "%s/%s" % (deployment_yaml_path, namespace)
    if not os.path.exists(file_path): os.mkdir(file_path)
    deploymentfile = "%s/deploy-%s.yaml" % (file_path, servicename)
    with open(deploymentfile, 'w') as f:
      yaml.dump(deployment, f, allow_unicode=True)
    return deploymentfile

def main():
  # # 获取传递的结构化字符串 {}
  args = sys.argv
  # # 降字符串结构化
  #args = json.loads(args)

  #appconf = "/home/k8s/env.yaml"
  #servicename = "ai-admin"
  #image = "registry-vpc.cn-beijing.aliyuncs.com/ygcx/aicenter:a243"
  #namespace = "pre"
  #servicename = args['servicename'] 
  #image = args['image']
  #namespace = args['namespace'] 
  #appconf = args['appconf']

  servicename = args[1] 
  image = args[2]
  namespace = args[3] 
  appconf = args[4]

  # gpu主机标签 node-deploy-app=all
  nodeDeployAppLabel = "all"
  if servicename == "ai-model-asr-denoise-gpu" and "pro" in namespace: nodeDeployAppLabel = "ai-model-asr-denoise-gpu"

  Deploy_obj = Deploy(appconf)
  deployment = Deploy_obj.deploymentYaml(servicename, image=image, namespace=namespace, nodeDeployAppLabel=nodeDeployAppLabel)
  #if namespace == "pro": deployment = Deploy_obj.updateDeployment(deployment)
  deployment = Deploy_obj.updateDeployment(deployment, namespace)
  # print(deployment)
  deploymentfile = Deploy_obj.writeFile(servicename, deployment, namespace)
  print(deploymentfile)

if __name__ == "__main__":
  main()
